package com.zhisheng.gufei.produce.service.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import net.sf.json.JSONArray;

import org.springframework.stereotype.Service;

import com.zhisheng.core.service.impl.BaseServiceImpl;
import com.zhisheng.gufei.city.dao.CityDao;
import com.zhisheng.gufei.city.entity.City;
import com.zhisheng.gufei.city.entity.JsonCity;
import com.zhisheng.gufei.grabagesort.dao.GrabageSortDao;
import com.zhisheng.gufei.grabagesort.entity.GrabageSort;
import com.zhisheng.gufei.produce.dao.GrabageProduceDestInfoDao;
import com.zhisheng.gufei.produce.dao.GrabageStatDao;
import com.zhisheng.gufei.produce.entity.GrabageProduceDestInfo;
import com.zhisheng.gufei.produce.entity.GrabageStat;
import com.zhisheng.gufei.produce.service.GrabageStatService;

/**
 * @author xgye
 * @date 2009-9-12
 * @version $Id$
 */
@Service("grabageStatService")
@SuppressWarnings("unchecked")
public class GrabageStatServiceImpl extends BaseServiceImpl<GrabageStat, Integer, GrabageStatDao> implements GrabageStatService {

    @Resource
    private CityDao cityDao;
    
    @Resource
    private GrabageSortDao grabageSortDao; 
    
    @Resource
    private GrabageProduceDestInfoDao grabageProduceDestInfoDao;
    
    private List<GrabageStat> cache;
    
    public List<GrabageStat> getStatByCity() {
        List<City> allCity = cityDao.findByHql("from City c where c.parent.id = 1");
        List<JsonCity> allJsonCity = new ArrayList<JsonCity>();
        for(City city : allCity){
        	JsonCity jc = new JsonCity();
        	jc.setId(city.getId());
        	jc.setCityName(city.getCityName());
        	allJsonCity.add(jc);
        }
        if (allCity == null) {
            return new ArrayList<GrabageStat>();
        }
        
        List<GrabageProduceDestInfo> infoList = grabageProduceDestInfoDao.getPDListByCity(allCity);
        int i = 1;
        for(JsonCity city : allJsonCity){
        	city.setId(i);
        	i++;
        }
        List<GrabageStat> returnList = caculateStatDataForCity(infoList, allJsonCity);
        cache = returnList;
        
        return returnList;
    }
    
    public List<GrabageStat> getStatBySortId() {
        List<GrabageSort> allGrabage = grabageSortDao.findAll();
        if (allGrabage == null) {
            return new ArrayList<GrabageStat>();
        }
        
        List<GrabageProduceDestInfo> infoList = grabageProduceDestInfoDao.getPDListByGFList(allGrabage);
        
        return caculateStatData(infoList, allGrabage);
    }
    
    private List<GrabageStat> caculateStatDataForCity(List<GrabageProduceDestInfo> infoList, List<JsonCity> allCity) {
        Map<String, List<GrabageProduceDestInfo>> caculateInfo = new HashMap<String, List<GrabageProduceDestInfo>>();
        
        //split infoList by grabage code
        for (GrabageProduceDestInfo info : infoList) {
            if (info.getCorperation() == null || info.getCorperation().getAreaCode() == null) {
                continue;
            }
            
            List<GrabageProduceDestInfo> underThisCode = caculateInfo.get(info.getCorperation().getAreaCode());
            if (underThisCode == null) {
                underThisCode = new ArrayList<GrabageProduceDestInfo>();
                caculateInfo.put(info.getCorperation().getAreaCode(), underThisCode);
            }
            underThisCode.add(info);
        }
        
        List<GrabageStat> statList = new ArrayList<GrabageStat>();
        for (JsonCity city : allCity) {
            List<GrabageProduceDestInfo> tmpList = caculateInfo.get(String.valueOf(city.getId()));
            GrabageStat stat = new GrabageStat();
            
            stat.setCity(city);
            if (tmpList != null) {
                stat.setAllStockAmount(getAllStatAmount(tmpList, "getStockAmountYears"));
                stat.setEmissionAmount(getAllStatAmount(tmpList, "getEmissionAmount"));
                stat.setDisposeAmount(getAllStatAmount(tmpList, "getDisposeAmount"));
                stat.setDisposePast(getAllStatAmount(tmpList, "getDisposeStockPast"));
                stat.setProductAmount(getAllStatAmount(tmpList, "getProduceAmount"));
                stat.setUseAmount(getAllStatAmount(tmpList, "getUtilizedAmount"));
                stat.setStockAmount(getAllStatAmount(tmpList, "getStockAmount"));
            } 
            
            statList.add(stat);
        }
        return statList;
    }
    
    private List<GrabageStat> caculateStatData(List<GrabageProduceDestInfo> infoList, List<GrabageSort> allGrabage) {
        Map<String, List<GrabageProduceDestInfo>> caculateInfo = new HashMap<String, List<GrabageProduceDestInfo>>();
        
        //split infoList by grabage code
        for (GrabageProduceDestInfo info : infoList) {
            List<GrabageProduceDestInfo> underThisCode = caculateInfo.get(info.getGrabage().getCode());
            if (underThisCode == null) {
                underThisCode = new ArrayList<GrabageProduceDestInfo>();
                caculateInfo.put(info.getGrabage().getCode(), underThisCode);
            }
            underThisCode.add(info);
        }
        
        List<GrabageStat> statList = new ArrayList<GrabageStat>();
        for (GrabageSort sort : allGrabage) {
            List<GrabageProduceDestInfo> tmpList = caculateInfo.get(sort.getCode());
            GrabageStat stat = new GrabageStat();
            
            stat.setGrabage(sort);
            if (tmpList != null) {
                stat.setAllStockAmount(getAllStatAmount(tmpList, "getStockAmountYears"));
                stat.setEmissionAmount(getAllStatAmount(tmpList, "getEmissionAmount"));
                stat.setDisposeAmount(getAllStatAmount(tmpList, "getDisposeAmount"));
                stat.setDisposePast(getAllStatAmount(tmpList, "getDisposeStockPast"));
                stat.setProductAmount(getAllStatAmount(tmpList, "getProduceAmount"));
                stat.setUseAmount(getAllStatAmount(tmpList, "getUtilizedAmount"));
                stat.setStockAmount(getAllStatAmount(tmpList, "getStockAmount"));
            } 
            
            statList.add(stat);
        }
        return statList;
    }
    
    private Float getAllStatAmount(List<GrabageProduceDestInfo> tmpList, String methodName) {
        Float result = 0f;
        try {
            for (GrabageProduceDestInfo info : tmpList) {
                Class clazz = info.getClass();
                Method method = clazz.getDeclaredMethod(methodName, new Class[]{});
                Float amount = (Float) method.invoke(info, new Object[]{});
                result += amount==null?0:amount;
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        
        return result;
    }

    public void setGrabageStatDao(GrabageStatDao grabageStatDao) {
        this.entityDao = grabageStatDao;
    }

    public String getAllJsonDataByCity() {
        Object obj = cache != null ? cache : this.getStatByCity();
        String jsonData = JSONArray.fromObject(obj).toString().replace("\\r\\n", "");
        
        cache = null;
        return jsonData;
    }

    public List<GrabageProduceDestInfo> getStatByCityId(Integer id) {
        List<City> allCity = new ArrayList<City>();
        City city = new City();
        city.setId(id);
        
        allCity.add(city);
        List<GrabageProduceDestInfo> infoList = grabageProduceDestInfoDao.getPDListByCity(allCity);
        
        return infoList;
    }
}
